using Pdf2epub.ExtractStrategy;
using Pdf2epub.Interfaces;
using System.Collections.Generic;
using System.ComponentModel;

namespace Pdf2epub.Model
{
    public class ContentBlock : BaseObject
    {
        private static int s_SequenceNumber;
        private readonly List<ContentBlock> m_SubBlocks = new List<ContentBlock>();
        private Chapter m_Chapter;
        private string m_Content;
        private HtmlReplacement m_DefaultReplacement;
        private float m_FirstChunkBaseLine;
        private FontUsage m_Font;
        private FontAssignmentData m_FontAssignment;
        private HtmlReplacement m_HtmlReplacement;
        private HtmlReplacementTag m_HtmlTagOverride = HtmlReplacementTag.None;
        private bool m_JoinWithPreviousBlock;
        private float m_LastChunkBaseLine;
        private float m_OriginalXPosition;
        private int m_SequenceNumber = GetSequenceNumber();
        private int m_SourcePage;
        private string m_StyleNameOverride;

        public ContentBlock()
        {
        }

        public ContentBlock(IProjectContext projectContext, ContentType contentType, string content)
            : base(projectContext)
        {
            ContentType = contentType;
            Content = content;
        }

        public ContentBlock(IProjectContext projectContext, ContentType contentType)
            : base(projectContext)
        {
            ContentType = contentType;
        }

        public ContentBlock(IProjectContext projectContext, ContentType contentType, string content, FontUsage font)
            : base(projectContext)
        {
            ContentType = contentType;
            Content = content;
            Font = font;
        }

        public ContentBlock(IProjectContext projectContext, ContentType contentType, FontUsage fontUsage)
            : base(projectContext)
        {
            ContentType = contentType;
            Content = string.Empty;
            Font = fontUsage;
        }

        [ReadOnly(true)]
        public Chapter Chapter
        {
            get { return m_Chapter; }
            set
            {
                m_Chapter = value;
                OnPropertyChanged("Chapter");
            }
        }

        public string Content
        {
            get { return m_Content; }
            set
            {
                m_Content = value;
                if (m_Content != null)
                    m_Content = m_Content.Replace("\0", "");
                OnPropertyChanged("Content");
            }
        }

        [ReadOnly(true)]
        public ContentType ContentType { get; set; }

        public HtmlReplacement DefaultReplacement
        {
            get
            {
                if (m_DefaultReplacement != null)
                    return m_DefaultReplacement;

                if (m_FontAssignment != null)
                {
                    m_FontAssignment.PropertyChanged -= OnFontAssignmentChanged;
                }

                if (m_HtmlReplacement != null)
                {
                    m_HtmlReplacement.PropertyChanged -= OnHtmlReplacementChanged;
                }

                m_DefaultReplacement = ProjectContext.ProjectConfiguration.HtmlReplacements[".none"];
                if (ProjectContext.ProjectConfiguration.FontAssignmentDataCollection.Contains(Font))
                {
                    m_FontAssignment = ProjectContext.ProjectConfiguration.FontAssignmentDataCollection[Font];
                    m_FontAssignment.PropertyChanged += OnFontAssignmentChanged;

                    string replacementStyle = m_FontAssignment.HtmlReplacementStyle;
                    if (ProjectContext.ProjectConfiguration.HtmlReplacements.Contains(replacementStyle))
                    {
                        m_HtmlReplacement = ProjectContext.ProjectConfiguration.HtmlReplacements[replacementStyle];
                        m_HtmlReplacement.PropertyChanged += OnHtmlReplacementChanged;
                        m_DefaultReplacement = m_HtmlReplacement;
                    }
                }
                return m_DefaultReplacement;
            }
        }

        [ReadOnly(true)]
        public float FirstChunkBaseLine
        {
            get { return m_FirstChunkBaseLine; }
            set
            {
                m_FirstChunkBaseLine = value;
                OnPropertyChanged("FirstChunkBaseLine");
            }
        }

        [ReadOnly(true)]
        public FontUsage Font
        {
            get { return m_Font; }
            set
            {
                m_Font = value;

                OnPropertyChanged("Font");

                m_DefaultReplacement = null;

                OnPropertyChanged("DefaultReplacement");
                OnPropertyChanged("HtmlTag");
                OnPropertyChanged("HtmlTagOverride");
                OnPropertyChanged("StyleName");
                OnPropertyChanged("StyleNameOverride");
            }
        }

        [ReadOnly(true)]
        public HtmlReplacementTag HtmlTag
        {
            get
            {
                if (HtmlTagOverride != HtmlReplacementTag.None)
                    return HtmlTagOverride;
                return DefaultReplacement.Tag;
            }
            set
            {
                HtmlTagOverride = value;
                OnPropertyChanged("HtmlTag");
            }
        }

        public HtmlReplacementTag HtmlTagOverride
        {
            get { return m_HtmlTagOverride; }
            set
            {
                m_HtmlTagOverride = value;
                OnPropertyChanged("HtmlTag");
                OnPropertyChanged("HtmlTagOverride");
            }
        }

        public bool JoinWithPreviousBlock
        {
            get { return m_JoinWithPreviousBlock; }
            set
            {
                m_JoinWithPreviousBlock = value;
                OnPropertyChanged("JoinWithPreviousBlock");
            }
        }

        [ReadOnly(true)]
        public float LastChunkBaseLine
        {
            get { return m_LastChunkBaseLine; }
            set
            {
                m_LastChunkBaseLine = value;
                OnPropertyChanged("LastChunkBaseLine");
            }
        }

        [ReadOnly(true)]
        public float OriginalXPosition
        {
            get { return m_OriginalXPosition; }
            set
            {
                m_OriginalXPosition = value;
                OnPropertyChanged("OriginalXPosition");
            }
        }

        [ReadOnly(true)]
        public int SequenceNumber
        {
            get { return m_SequenceNumber; }
            set { m_SequenceNumber = value; }
        }

        [ReadOnly(true)]
        public int SourcePage
        {
            get { return m_SourcePage; }
            set
            {
                m_SourcePage = value;
                OnPropertyChanged("SourcePage");
            }
        }

        [ReadOnly(true)]
        public string StyleName
        {
            get
            {
                if (!string.IsNullOrEmpty(StyleNameOverride))
                    return StyleNameOverride;
                return DefaultReplacement.StyleName;
            }
            set
            {
                StyleNameOverride = value;
                OnPropertyChanged("StyleName");
            }
        }

        [ReadOnly(true)]
        public string StyleNameOverride
        {
            get { return m_StyleNameOverride; }
            set
            {
                m_StyleNameOverride = value;
                OnPropertyChanged("StyleNameOverride");
                OnPropertyChanged("StyleName");
            }
        }

        [Browsable(false)]
        public List<ContentBlock> SubBlocks
        {
            get { return m_SubBlocks; }
        }

        public void Append(string newContent)
        {
            Content = string.Format("{0}{1}", Content, newContent);
        }

        public void BroadcastPropertyUpdate(string propertyName)
        {
            OnPropertyChanged(propertyName);
        }

        public override string ToString()
        {
            return string.Format("{0} ({1}: '{2}')", base.ToString(), ContentType, Content);
        }

        public void TriggerRefresh(string propertyName)
        {
            OnPropertyChanged(propertyName);
        }

        private static int GetSequenceNumber()
        {
            s_SequenceNumber++;
            return s_SequenceNumber;
        }

        private void ForceUpdateFontRelatedProperties()
        {
            m_DefaultReplacement = null;

            OnPropertyChanged("DefaultReplacement");
            OnPropertyChanged("HtmlTag");
            OnPropertyChanged("StyleName");
        }

        private void OnFontAssignmentChanged(object sender, PropertyChangedEventArgs e)
        {
            ForceUpdateFontRelatedProperties();
        }

        private void OnHtmlReplacementChanged(object sender, PropertyChangedEventArgs e)
        {
            ForceUpdateFontRelatedProperties();
        }
    }
}